package me.qi.kancha.security.authorities;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import me.qi.kancha.mapper.EntityAccountMapper;
import me.qi.kancha.mapper.EntityRoleMapper;
import me.qi.kancha.mapper.RoleRuleMapper;
import me.qi.kancha.mapper.RuleAllowMapper;
import me.qi.kancha.dto.core.EntityAccountDTO;
import me.qi.kancha.dto.core.EntityRoleDTO;
import me.qi.kancha.dto.core.RoleRuleDTO;
import me.qi.kancha.dto.core.RuleAllowDTO;
import com.xhyt.common.resource.support.PermitObject;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author sun
 * @date 2022/1/19 23:49
 * @modified By：
 */
@Component
public class PermitServiceImpl implements PermitService {

    private final EntityRoleMapper entityRoleMapper;

    private final RoleRuleMapper roleRuleMapper;

    private final RuleAllowMapper ruleAllowMapper;

    private final EntityAccountMapper entityAccountMapper;

    public PermitServiceImpl(EntityRoleMapper entityRoleMapper, RoleRuleMapper roleRuleMapper,
                             RuleAllowMapper ruleAllowMapper, EntityAccountMapper entityAccountMapper) {
        this.entityRoleMapper = entityRoleMapper;
        this.roleRuleMapper = roleRuleMapper;
        this.ruleAllowMapper = ruleAllowMapper;
        this.entityAccountMapper = entityAccountMapper;
    }

    @Override
    public List<PermitObject> getPermit(String clientId, String grantType, String aid) {
        List<PermitObject> result = new ArrayList<>();
        //主体
        List<String> ids = entityIdList(clientId, grantType, aid);
        if (ids.isEmpty()) {
            return result;
        }
        //根据主体查询权限
        List<String> ruleCodes = getRuleCodes(ids);
        if (ruleCodes.isEmpty()) {
            return result;
        }
        //查询许可
        LambdaQueryWrapper<RuleAllowDTO> allowWrapper = new LambdaQueryWrapper<>();
        List<RuleAllowDTO> ruleAllowList = ruleAllowMapper.selectList(allowWrapper.in(RuleAllowDTO::getRuleCode, ruleCodes));

        return ruleAllowList.stream().map(allowDTO -> {
            PermitObject permitObject = new PermitObject();
            permitObject.setMethod(allowDTO.getMethod());
            permitObject.setUrl(allowDTO.getUrl());
            permitObject.setServerName(allowDTO.getServerName());
            return permitObject;
        }).collect(Collectors.toList());
    }

    /**
     * 根据主体查询权限
     *
     * @param ids
     * @return
     */
    private List<String> getRuleCodes(List<String> ids) {
        List<String> rules = new ArrayList<>();
        //查询角色
        LambdaQueryWrapper<EntityRoleDTO> entityRoleWrapper = new LambdaQueryWrapper<>();
        List<EntityRoleDTO> entityRoleList = entityRoleMapper.selectList(entityRoleWrapper.in(EntityRoleDTO::getEntityId, ids));
        if (!entityRoleList.isEmpty()) {
            //查询角色关联权限
            List<String> roles = entityRoleList.stream().map(EntityRoleDTO::getRoleCode).collect(Collectors.toList());
            LambdaQueryWrapper<RoleRuleDTO> roleRuleWrapper = new LambdaQueryWrapper<>();
            List<RoleRuleDTO> roleRuleDTOS = roleRuleMapper.selectList(roleRuleWrapper.in(RoleRuleDTO::getRoleCode, roles));
            if (!roleRuleDTOS.isEmpty()) {
                rules = roleRuleDTOS.stream().map(RoleRuleDTO::getRuleCode).collect(Collectors.toList());
            }
        }
        return rules;
    }

    /**
     * 查询主体id
     *
     * @param clientId
     * @param grantType
     * @param aid
     * @return
     */
    private List<String> entityIdList(String clientId, String grantType, String aid) {
        List<String> ids = new ArrayList<>();
        if (!ObjectUtils.isEmpty(clientId) && !ObjectUtils.isEmpty(grantType)) {
            //客户端主体
            ids.add(String.format("%s:%s", clientId, grantType));
        }
        if (!ObjectUtils.isEmpty(aid) ) {
            //查询账号关联主体
            LambdaQueryWrapper<EntityAccountDTO> entityAccountWrapper = new LambdaQueryWrapper<>();
            List<EntityAccountDTO> list = entityAccountMapper.selectList(entityAccountWrapper.eq(EntityAccountDTO::getAccountId, aid));
            if(!list.isEmpty()) {
                ids.addAll(list.stream().map(EntityAccountDTO::getEntityId).collect(Collectors.toList()));
            }
        }
        return ids;
    }
}
